/*
 * Created on 10-sep-2004
 *
 */
package guru.merlin.core;

import java.util.Date;

import guru.util.Commander;

import org.apache.log4j.Logger;

/**
 * @author cobach
 *  
 */
public class Router implements EnvelopeHandler{
    Logger logger = Logger.getLogger(Router.class);
    private Route FAULT_ROUTE = new Route("internalFaultRoute");

    private RoutingTableHandler routingTable;
    private EnvelopeHandler handler;

    public Router(EnvelopeHandler h, Commander commander, String xmlRoutingTableFilePath) throws RuleSyntaxErrorException {
        handler = h;

        routingTable = new RoutingTableHandler(commander.getValue("router.routingTable"), new RuleEvaluator());

    }

    public Object handEnvelope(Envelope envelope) throws CantHandException {
        String msg = "";
        try {
            envelope = preRouteEnvelope(envelope);
            envelope.setDestinationRoute(routeEnvelope(envelope));
            if (logger.isDebugEnabled()) {
                msg = "Mensaje enrutado a:'" + envelope.getDestinationRoute().toString() + "'";
                logger.debug(msg);
            }
            getHandler().handEnvelope(envelope);
        } catch (CantHandException e) {
            logger.error("Error de enturamiento: " + e);
            e.printStackTrace();
            handleError(envelope, e, "Handling Error");
        } catch (Throwable e) {
            logger.error("Error Interno: " + e);
            e.printStackTrace();
            handleError(envelope, new CantHandException("Internal Error: " + e), "Internal Error");
        } finally{

        }
        return envelope;
    }

    public Envelope preRouteEnvelope(Envelope envelope) throws CantHandException {
        return (envelope);
    }

    public Route routeEnvelope(Envelope envelope) throws CantHandException {
        String msg = "";
        if (logger.isDebugEnabled()) {
            msg = "Mensaje recibido por enrutador: " + envelope.toString();
            logger.debug(msg);
        }
        try {
            Date begin = new Date();
            String routeId = routingTable.firstRute2Comply(envelope);

            envelope.setRoutingTime(new Date().getTime() - begin.getTime());
            return (new Route(routeId));

        } catch (Exception e) {
            e.printStackTrace();
            throw new CantHandException("reason: " + e);
        }
    }

    public EnvelopeHandler getHandler() {
        return handler;
    }

    public String getVersion() {
        return ("Merlin Router v2.0");
    }

    public void handleError(Envelope envelope, Throwable track, String reason) {
        envelope.setDestinationRoute(FAULT_ROUTE);
        envelope.setComment(reason);
        envelope.setThrowable(track);
        try {
            getHandler().handEnvelope(envelope);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("Could not store envelope on FAULT QUEUE!: " + envelope);
        }
    }

    /**
     * Ejecuta un procesamiento previo a la ejecucin de la accin sobre el objeto envelope.
     * 
     * @param envelope
     * @return un objeto referencia del preprocesamiento.
     * @throws Exception
     */
    public Object preProcesingAction(Envelope envelope) throws Exception {
        return null;
    }

    /**
     * Ejecuta un procesamiento posterior a la ejecucin de la accin sobre el objeto envelope.
     * 
     * @param envelope
     * @return un objeto referencia del postprocesamiento.
     * @throws Exception
     */
    public Object postProcesingAction(Envelope envelope) throws Exception {
        return null;
    }

    /**
     * Efecta una especie de rollback del preprocesamiento realizado, valindose del objeto
     * referencia.
     * 
     * @param actionReference
     *            Objeto referencia del preprocesamiento realizado.
     * @throws Exception
     */
    public void preProcesingActionCompensator(Object actionReference) throws Exception {

    }

    /**
     * Efecta una especie de rollback del postprocesamiento realizado, valindose del objeto
     * referencia.
     * 
     * @param actionReference
     *            Objeto referencia del postprocesamiento realizado.
     * @throws Exception
     */
    public void postProcesingActionCompensator(Object actionReference) throws Exception {

    }

    /*
     * (sin Javadoc)
     * 
     * @see guru.merlin.core.EnvelopeHandler#retrieveEnvelope(java.lang.Object)
     */
    public void retrieveEnvelope(Object EnvelopeReference) throws CantHandException {
    }

    /**
     * Hace persistente el procesamientos de un objeto Envelope.
     * 
     * @param EnvelopeReference.
     *            Referencia al Envelope que fue procesado.
     * @throws CantHandException
     */
    public void commitHandEnvelope(Object EnvelopeReference) throws CantHandException {
    }

    /**
     * Hace persistente el precesamientos de un objeto Envelope.
     * 
     * @param actionReference
     *            Objeto referencia del preprocesamiento realizado.
     * @throws CantHandException
     */
    public void commitPreProcesingAction(Object actionReference) throws EPException {
    }

    /**
     * Hace persistente el postcesamientos de un objeto Envelope.
     * 
     * @param actionReference
     *            Objeto referencia del postprocesamiento realizado.
     * @throws CantHandException
     */
    public void commitPostProcesingAction(Object actionReference) throws EPException {
    }

}